package net.esj.basic.core.engine.util;

import java.lang.management.LockInfo;
import java.lang.management.ManagementFactory;
import java.lang.management.MonitorInfo;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * @author -Nemesiss- L2M
 *
 */
public class DeadLockDetector extends Thread
{
	private static Logger _log = Logger.getLogger(DeadLockDetector.class.getName());

	private static final int _sleepTime = 1000;

	private final ThreadMXBean tmx;

	public DeadLockDetector()
	{
		super("DeadLockDetector");
		tmx = ManagementFactory.getThreadMXBean();
	}

	@Override 
	public final void run()
	{
		boolean deadlock = false;
		while(!deadlock)
		{
			try
			{
				long[] ids = tmx.findDeadlockedThreads();

				if(ids != null)
				{
					deadlock = true;
					ThreadInfo[] tis = tmx.getThreadInfo(ids,true,true);
					String info = "DeadLock Found!\n";
					for(ThreadInfo ti : tis)
					{
						info += ti.toString();
					}

					for(ThreadInfo ti : tis)
					{
						LockInfo[] locks = ti.getLockedSynchronizers();
						MonitorInfo[] monitors = ti.getLockedMonitors();
						if(locks.length == 0 && monitors.length == 0)
						{
							continue;
						}

						ThreadInfo dl = ti;
						info += "Java-level deadlock:\n";
						info += "\t"+dl.getThreadName()+" is waiting to lock "+dl.getLockInfo().toString()+" which is held by "+dl.getLockOwnerName()+"\n";
						while((dl = tmx.getThreadInfo(new long[]{dl.getLockOwnerId()},true,true)[0]).getThreadId() != ti.getThreadId())
						{
							info += "\t"+dl.getThreadName()+" is waiting to lock "+dl.getLockInfo().toString()+" which is held by "+dl.getLockOwnerName()+"\n";
						}
					}
					_log.warning(info);

				}
				Thread.sleep(_sleepTime); 
			}
			catch(Exception e)
			{
				_log.log(Level.WARNING,"DeadLockDetector: ",e);
			}
		}
	}
}
